package com.dyh.quickdemozwei;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
public class TestIOManger {


    @Setter@Getter
   static abstract class StandardIO{
       private static final int STATUS_INIT = 0;
       private static final int STATUS_TRAP = 1;
       private static final int STATUS_NO_TRAP = 2;
//       private static final int STATUS_COMPLETE = 2;

       protected int status;
       public final void start() throws InterruptedException{
           status = STATUS_TRAP;
           work();
           status = STATUS_NO_TRAP;
       }

       abstract protected void work();
       abstract boolean isComplete();
       abstract void onComplete();
    }


    static class IoInterchangeThread extends Thread{
        private final long frame;
        private  final   int slot;
        private volatile int status;
        private  StandardIO[] ios;





        private static final int STATUS_INIT = 0;
        private static final int STATUS_TRAP = 1;

        private static final long OFFSET_STATUS;
        private static final Unsafe U;
        private static final    long ABASE;//16
        private static  final long ASHIFT;

        static {
            try {
                Field field = Unsafe.class.getDeclaredField("theUnsafe");
                field.setAccessible(true);

                U =  (Unsafe) field.get(null);

                Class<?> ak =   StandardIO[].class;
                ABASE = U.arrayBaseOffset(ak);

                int scale = U.arrayIndexScale(ak);//4

                ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);


                Class<?> k = IoInterchangeThread.class;
                OFFSET_STATUS = U.objectFieldOffset
                        (k.getDeclaredField("status"));

            }catch (Exception e){
                throw new Error(e);
            }

        }


        public IoInterchangeThread(long frame,int slot) {
            this.frame = frame;
            this.slot = slot;
            ios=new StandardIO[slot];
        }

        public boolean checkStatus(int status){
            return status==this.status;
        }



        public void apply(StandardIO io){
            for (;;){
                for (int i = 0;i< slot;i++){
                    if (ios[i]==null){
                        long offset =  ((long)i << ASHIFT) + ABASE;

                        if (U.compareAndSwapObject(ios,offset,null,io)){
//                            status=STATUS_TRAP;
//                            log.info("start-1");
//                            io.start();
//                            log.info("start-2");
//                            status=STATUS_INIT;
                            return;
                        }

                    }
                }
            }

        }

        @Override
        public void run() {
            for (;;){

                for (int i = 0;i< slot;i++) {
                    StandardIO io = ios[i];
                    if (io==null)
                        continue;
                    if (io.getStatus()==StandardIO.STATUS_INIT){
                        status = STATUS_TRAP;
                        try {
                            io.start();
                        } catch (InterruptedException e) {
                            //dawdaw
                        }

                        status = STATUS_INIT;
                    }
                }


                for (int i = 0;i< slot;i++){
                    StandardIO io = ios[i];
                    if (io==null)
                        continue;
                    if (!io.isComplete())
                        continue;
                    io.onComplete();
//                    long offset =  ((long)i << ASHIFT) + ABASE;
//                    U.compareAndSwapObject(ios,offset,null,io);
                    ios[i] = null;
                }

                try {
                    Thread.sleep(frame);
                } catch (InterruptedException e) {
//                    e.printStackTrace();
                    log.info("frame sleep interrupted");
                    //不打印了 否则一堆被monitor打断的日志
                }

            }
        }
    }

    static class IoTrapMonitorThread extends  Thread{
        private final long frame;
        private final long wait;
        IoInterchangeThread[] ioInterchangeThreads;

        private final Map<IoInterchangeThread,Long> lastTimeMap=new HashMap<>();

        public IoTrapMonitorThread(long frame,long wait,IoInterchangeThread... ioInterchangeThreads) {
            this.frame = frame;
            this.wait = wait;
            this.ioInterchangeThreads = ioInterchangeThreads;
        }

        @Override
        public void run() {
            for (;;){
                for (IoInterchangeThread ioInterchangeThread : ioInterchangeThreads) {
                    Long lastTime = lastTimeMap.get(ioInterchangeThread);
                    if (lastTime==null){
                        if (ioInterchangeThread.checkStatus(IoInterchangeThread.STATUS_TRAP)){
                            lastTimeMap.put(ioInterchangeThread,System.currentTimeMillis());
                        }

                    }
                    else {
                        if (System.currentTimeMillis()-lastTime>=wait){
                            ioInterchangeThread.interrupt();
                            lastTimeMap.put(ioInterchangeThread,null);
                        }
                    }

                }
                try {
                    Thread.sleep(frame);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }


        }
    }

    static class DemoIO extends StandardIO{
        String name;
        long time;
        String res;

        public DemoIO(String name, long time) {
            this.name = name;
            this.time = time;
        }

        @Override
        protected void work() {
            log.info("IO name={} 开始",name);
            /*单纯为了模拟IO*/
            new Thread(()->{
                for (;;){
                    try {
                        Thread.sleep(time);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    this.res = "dawkdhawwkduawd";
                    break;
                }
            }).start();
        }

        @Override
        public boolean isComplete() {
            return res!=null;
        }

        @Override
        public void onComplete() {
            log.info("IO name={} 完成! {}",name,res);
        }


    }

    static class DemoTrapIO extends StandardIO{
        String name;
        long time;
        String res;

        public DemoTrapIO(String name, long time) {
            this.name = name;
            this.time = time;
        }

        @Override
        protected void work() {
            log.info("IO name={} 开始",name);
            /*单纯为了模拟IO*/
            Thread t = new Thread(()->{
                for (;;){
                    try {
                        Thread.sleep(time);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    this.res = "dawkdhawwkduawd";
                    break;
                }
            });

            t.start();
            try {
                t.join();
            } catch (InterruptedException e) {
//                log.info("{} 从等待IO中被打断",Thread.currentThread().getName());
            }
        }

        @Override
        public boolean isComplete() {
            return res!=null;
        }

        @Override
        public void onComplete() {
            log.info("IO name={} 完成! {}",name,res);
        }


    }


    @Test public void test2() throws InterruptedException {
        IoInterchangeThread interchangeThread = new IoInterchangeThread(200L,3);
        interchangeThread.setName("专门处理io的线程");

        IoTrapMonitorThread trapMonitorThread = new IoTrapMonitorThread(100L,50L,interchangeThread);
        trapMonitorThread.setName("监视IO阻塞的线程");

        interchangeThread.start();
        trapMonitorThread.start();

        interchangeThread.apply(new DemoTrapIO("1s的IO",1000));
        interchangeThread.apply(new DemoTrapIO("3s的IO",3000));
        interchangeThread.apply(new DemoTrapIO("1s的IO-2",1000));
        interchangeThread.apply(new DemoTrapIO("2s的IO",2000));

        interchangeThread.join();
    }

    @Test public void test() throws InterruptedException {
        IoInterchangeThread interchangeThread = new IoInterchangeThread(200L,3);
        interchangeThread.setName("专门处理io的线程");
        interchangeThread.start();

        interchangeThread.apply(new DemoIO("1s的IO",1000));
        interchangeThread.apply(new DemoIO("3s的IO",3000));
        interchangeThread.apply(new DemoIO("1s的IO-2",1000));
        interchangeThread.apply(new DemoIO("2s的IO",2000));

        interchangeThread.join();
    }


    public static void main(String[] args) {
//        Map<String,String> map = new HashMap<>();
//        map.putIfAbsent("1","aa");
//        map.putIfAbsent("1","bb");
//
//        System.out.println();

        String str = "[[\"inventory_m\",null,102]]";

        JSONArray ja = JSONObject.parseArray(str);

        System.out.println();

    }
//    class BusySwichException extends RuntimeException{
//
//    }
//
//    @Test
//    public void test() throws InterruptedException {
//        Object[] output = new Object[1];//为了让r1 可以修改
//
//
//        Runnable io1 = ()->{
//            log.info("耗时io操作开始");
//            int i =0;
//            for (;;){
//
//                try {
//                    Thread.sleep(1000L);
//
//                } catch (InterruptedException e) {
//                    log.info("InterruptedException!");//假设这里是不能被打断的IO
//                }
//                if (i++>4)
//                    break;
//            }
//            output[0]="dawdaWdawdawdawd";
//
//            log.info("耗时io操作结束");
//        };
//
//        Runnable r1 = ()->{
//
//            io1.run();
//        };
//
//        Thread t1 = new Thread(r1);
//        t1.setName("t1");
//        t1.start();
//        try {
//            Thread.sleep(1000L);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//
//        t1.interrupt();
//
//
//        t1.join();
//
//        log.info("join over");
//
//        Thread.sleep(5000L);
//
//        log.info("output={}",output[0]);
//    }
}
